package com.zenithmind.common.security;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import jakarta.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 默认安全规则加载器实现
 * 为微服务提供基本的安全规则
 */
@Slf4j
@Component
public class DefaultSecurityRuleLoader implements SecurityRuleLoader {

    @Value("${spring.application.name:unknown}")
    private String serviceCode;

    private List<RequestMatcher> publicPaths = new ArrayList<>();

    private List<SecurityRule> roleRules = new ArrayList<>();
    
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    
    @PostConstruct
    public void init() {
        log.info("初始化默认安全规则加载器: {}", serviceCode);
        initDefaultRules();
    }
    


    @Override
    public List<RequestMatcher> getPublicPaths() {
        return publicPaths;
    }

    @Override
    public List<SecurityRule> getRoleBasedRules() {
        return roleRules;
    }

    @Override
    public void refreshRules() {
        log.info("刷新安全规则 (默认实现，无操作)");
        // 默认实现不做任何刷新
    }

    @Override
    public boolean isPublicPath(String path, String method) {
        // 检查是否匹配公开路径
        for (RequestMatcher matcher : publicPaths) {
            if (matcher instanceof AntPathRequestMatcher) {
                AntPathRequestMatcher antMatcher = (AntPathRequestMatcher) matcher;
                boolean pathMatched = antPathMatcher.match(antMatcher.getPattern(), path);
                
                // AntPathRequestMatcher不直接提供getHttpMethod方法，我们需要使用模拟请求来检查
                if (pathMatched) {
                    // 对于公开路径，我们通常不关心HTTP方法
                    return true;
                }
            }
        }
        
        return false;
    }

    @Override
    public List<String> getRequiredRoles(String path, String method) {
        // 检查是否匹配角色规则
        for (SecurityRule rule : roleRules) {
            RequestMatcher matcher = rule.getPathMatcher();
            if (matcher instanceof AntPathRequestMatcher) {
                AntPathRequestMatcher antMatcher = (AntPathRequestMatcher) matcher;
                boolean pathMatched = antPathMatcher.match(antMatcher.getPattern(), path);
                
                if (pathMatched) {
                    return rule.getRequiredRoles();
                }
            }
        }
        
        // 默认不需要特定角色
        return Collections.emptyList();
    }

    @Override
    public String getServiceCode() {
        return serviceCode;
    }

    @Override
    public void setServiceCode(String serviceCode) {
        this.serviceCode = serviceCode;
    }

    @Override
    public void addPublicPath(String pathPattern) {
        publicPaths.add(new AntPathRequestMatcher(pathPattern));
        log.debug("添加公共路径: {}", pathPattern);
    }

    @Override
    public void addPublicPath(String pathPattern, String httpMethod) {
        publicPaths.add(new AntPathRequestMatcher(pathPattern, httpMethod));
        log.debug("添加公共路径: {} [{}]", pathPattern, httpMethod);
    }

    @Override
    public void removePublicPath(String pathPattern) {
        publicPaths.removeIf(matcher -> {
            if (matcher instanceof AntPathRequestMatcher) {
                AntPathRequestMatcher antMatcher = (AntPathRequestMatcher) matcher;
                return antPathMatcher.match(antMatcher.getPattern(), pathPattern);
            }
            return false;
        });
        log.debug("移除公共路径: {}", pathPattern);
    }

    @Override
    public void addRoleRule(String pathPattern, List<String> roles) {
        SecurityRule rule = new SecurityRule();
        rule.setPathMatcher(new AntPathRequestMatcher(pathPattern));
        rule.setRequiredRoles(roles);
        roleRules.add(rule);
        log.debug("添加角色规则: {} -> {}", pathPattern, roles);
    }

    @Override
    public void addRoleRule(String pathPattern, String httpMethod, List<String> roles) {
        SecurityRule rule = new SecurityRule();
        rule.setPathMatcher(new AntPathRequestMatcher(pathPattern, httpMethod));
        rule.setRequiredRoles(roles);
        roleRules.add(rule);
        log.debug("添加角色规则: {} [{}] -> {}", pathPattern, httpMethod, roles);
    }

    @Override
    public void removeRoleRule(String pathPattern) {
        roleRules.removeIf(rule -> {
            if (rule.getPathMatcher() instanceof AntPathRequestMatcher) {
                AntPathRequestMatcher antMatcher = (AntPathRequestMatcher) rule.getPathMatcher();
                return antPathMatcher.match(antMatcher.getPattern(), pathPattern);
            }
            return false;
        });
        log.debug("移除角色规则: {}", pathPattern);
    }

    @Override
    public boolean hasPermission(String path, String method, List<String> userRoles) {
        // 检查是否为公开路径
        if (isPublicPath(path, method)) {
            return true;
        }

        // 检查角色权限
        List<String> requiredRoles = getRequiredRoles(path, method);
        if (requiredRoles == null || requiredRoles.isEmpty()) {
            return true; // 不需要特定角色
        }

        // 检查用户是否具有所需角色
        if (userRoles == null || userRoles.isEmpty()) {
            return false;
        }

        return userRoles.stream().anyMatch(requiredRoles::contains);
    }

    @Override
    public void initDefaultRules() {
        // 清空现有规则
        clearAllRules();

        // 添加默认的公开路径
        addPublicPath("/actuator/**");
        addPublicPath("/v3/api-docs/**");
        addPublicPath("/swagger-ui/**");
        addPublicPath("/swagger-ui.html");
        addPublicPath("/error");

        log.info("已初始化默认安全规则，公开路径数量: {}", publicPaths.size());
    }

    @Override
    public void clearAllRules() {
        publicPaths.clear();
        roleRules.clear();
        log.info("已清空所有安全规则");
    }

    @Override
    public SecurityRuleStatistics getRuleStatistics() {
        return new SecurityRuleStatistics(publicPaths.size(), roleRules.size(), serviceCode);
    }
} 